﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using Psm.Logging;
using Psm.Container;

namespace Psm.PubSub.Configuration
{
    public class PubSubConfiguration : ConfigurationSection
    {
        private static ILogger logger = Repository.GetInstance<ILogger>();
        private static PubSubConfiguration psmConfiguration;

        public static PubSubConfiguration Instance
        {
            get
            {
                return psmConfiguration;
            }
        }

        static PubSubConfiguration()
        {
            var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            psmConfiguration = (PubSubConfiguration)config.GetSection("PubSub/Topics");
            if( psmConfiguration != null )
                psmConfiguration.Intialize();
        }

        private void Intialize()
        {
            foreach (TopicConfiguration configuration in Topics)
                configuration.Intialize();
        }

        [ConfigurationProperty("", IsDefaultCollection = true, IsKey = false, IsRequired = true)]
        public TopicConfigurationCollection Topics
        {
            get
            {
                return base[""] as TopicConfigurationCollection;
            }

            set
            {
                base[""] = value;
            }
        }
    }

    public class TopicConfigurationCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new TopicConfiguration();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((TopicConfiguration)element).Name;
        }

        protected override string ElementName
        {
            get
            {
                return "Topic";
            }
        }

        protected override bool IsElementName(string elementName)
        {
            return !String.IsNullOrEmpty(elementName) && elementName == "Topic";
        }

        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.BasicMap;
            }
        }

        public TopicConfiguration this[int index]
        {
            get
            {
                return base.BaseGet(index) as TopicConfiguration;
            }
        }
    }

    public class TopicConfiguration : ConfigurationElement
    {
        private Dictionary<string, int> fieldIndexHash = new Dictionary<string, int>();
        private FieldConfiguration[] keys;

        public Dictionary<string, int> FieldIndexHash
        {
            get
            {
                return fieldIndexHash;
            }
        }

        public TopicConfiguration()
        {
        }

        [ConfigurationProperty("name", IsRequired = true, IsKey = true)]
        public string Name
        {
            get { return base["name"] as string; }
            set { base["name"] = value; }
        }


        [ConfigurationProperty("", IsDefaultCollection = true, IsKey = false, IsRequired = true)]
        public FieldCollection Fields
        {
            get
            {
                return base[""] as FieldCollection;
            }

            set
            {
                base[""] = value;
            }
        }

        public FieldConfiguration[] GetKeyFields()
        {
            return keys;
        }

        internal void Intialize()
        {
            int index = 0;
            foreach (FieldConfiguration field in Fields)
            {
                field.Index = index++;
                fieldIndexHash[field.Name] = field.Index;
                foreach (SynonymConfiguration synonym in field.Synonyms)
                {
                    fieldIndexHash[synonym.Name] = field.Index;
                }
            }

            List<FieldConfiguration> keys = new List<FieldConfiguration>();
            foreach (FieldConfiguration field in this.Fields)
            {
                if (field.IsKey)
                    keys.Add(field);
            }
            this.keys = keys.ToArray();
        }
    }

    public class FieldCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new FieldConfiguration();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((FieldConfiguration)element).Name;
        }

        protected override string ElementName
        {
            get
            {
                return "Field";
            }
        }

        protected override bool IsElementName(string elementName)
        {
            return !String.IsNullOrEmpty(elementName) && elementName == "Field";
        }

        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.BasicMap;
            }
        }

        public FieldConfiguration this[int index]
        {
            get
            {
                return base.BaseGet(index) as FieldConfiguration;
            }
        }
    }

    public class FieldConfiguration : ConfigurationElement
    {
        private int index = 0;

        public FieldConfiguration()
        {
        }

        [ConfigurationProperty("name", IsRequired = true, IsKey = true)]
        public string Name
        {
            get { return base["name"] as string; }
            set { base["name"] = value; }
        }

        [ConfigurationProperty("type", IsRequired = true, IsKey = false)]
        public string Type
        {
            get { return base["type"] as string; }
            set { base["type"] = value; }
        }

        [ConfigurationProperty("isKey", IsRequired = false, IsKey = false)]
        public bool IsKey
        {
            get { return (bool)base["isKey"]; }
            set { base["isKey"] = value; }
        }

        public int Index
        {
            get { return index; }
            set { index = value; }
        }

        [ConfigurationProperty("", IsDefaultCollection = true, IsKey = false, IsRequired = true)]
        public SynonymCollection Synonyms
        {
            get
            {
                return base[""] as SynonymCollection;
            }

            set
            {
                base[""] = value;
            }
        }

        public string GetFieldValue(Dictionary<string,string> data)
        {
            if (data.ContainsKey(this.Name))
                return data[this.Name];
            else
            {
                foreach (SynonymConfiguration synonym in this.Synonyms)
                {
                    if (data.ContainsKey(synonym.Name))
                        return data[synonym.Name];
                }
            }
            return null;
        }
      
    }



    public class SynonymCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new SynonymConfiguration();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((SynonymConfiguration)element).Name;
        }

        protected override string ElementName
        {
            get
            {
                return "Synonym";
            }
        }

        protected override bool IsElementName(string elementName)
        {
            return !String.IsNullOrEmpty(elementName) && elementName == "Synonym";
        }

        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.BasicMap;
            }
        }

        public SynonymConfiguration this[int index]
        {
            get
            {
                return base.BaseGet(index) as SynonymConfiguration;
            }
        }
    }


    public class SynonymConfiguration : ConfigurationElement
    {
        public SynonymConfiguration()
        {
        }

        [ConfigurationProperty("name", IsRequired = true, IsKey = true)]
        public string Name
        {
            get { return base["name"] as string; }
            set { base["name"] = value; }
        }
    }

}
